// 注意:
// 如果新增成员函数，需要同步修改 lang/cxx/private/cxx_helper.hpp: __batches_lambda
#ifndef xpack_utils_stream_wrapper
#define xpack_utils_stream_wrapper
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::utils_stream_wrapper::inc
#include"configure/limit.hpp"
#include"define/base_type.hpp"
#include"define/classify.hpp"
#include"interface/can_callback.hpp"
#include"macro/xexport.hpp"
#include"macro/xis_nullptr.hpp"
#include"macro/xstruct.hpp"
#include"math/minimum.hpp"
#include"memop/copy.hpp"
#include"memop/fill.hpp"
#include"meta/has_cast.hpp"
#pragma pop_macro("xuser")

namespace mixc::utils_stream_wrapper::origin{
    template<class item_t>
    xstruct(
        xtmpl(stream_wrapper, item_t),
        xwhos(inc::classify_t::utils_stream_wrapper)
    )
    private:
        item_t ** p_buffer;
    public:
        stream_wrapper(item_t ** p_buffer = nullptr) : p_buffer(p_buffer){}

        void output(item_t const * content, uxx length) const {
            inc::copy_with_operator_unsafe(*p_buffer, content, length);
            *p_buffer        += length;
        }

        void output(item_t const & value, uxx count = 1) const {
            inc::fill_with_operator(*p_buffer, value, count);
            *p_buffer        += count;
        }

        xis_nullptr(p_buffer == nullptr)
    $

    template<class item_t>
    xstruct(
        xtmpl(stream_wrapperx, item_t),

        // 需要和 stream_wrapper 的保持一致
        xwhos(inc::classify_t::utils_stream_wrapper)
    )
    private:
        using func_t    = void(item_t const * content, uxx length);
        using invoke_t  = inc::icallback<func_t>;
        invoke_t invoke;
    public:
        template<class callback_t>
        requires(inc::can_callback<callback_t, func_t>)
        stream_wrapperx(callback_t && invoke) : invoke(invoke){}

        stream_wrapperx(decltype(nullptr) = nullptr) : invoke(nullptr){}

        void output(item_t const * content, uxx length) const {
            invoke((item_t *)content, length);
        }

        void output(item_t const & value) const {
            invoke((item_t *)&value, 1);
        }

        void output(item_t const & value, uxx count) const {
            item_t temp[inc::limit::utils_stream_wrapper_output];

            for(uxx c = count; c;){
                uxx num         = inc::minimum<uxx>(c, inc::limit::utils_stream_wrapper_output);
                c              -= num;
                inc::fill_with_operator(temp, value, num);
                invoke(temp, num);
            }
        }

        xis_nullptr(invoke == nullptr)
    $

    template<class lambda_t, class item_t>
    constexpr bool can_stream = 
        inc::has_cast<stream_wrapper<item_t>, lambda_t> or
        inc::has_cast<stream_wrapperx<item_t>, lambda_t>;

}

#endif

xexport_space(mixc::utils_stream_wrapper::origin)
